﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Forums.OfflineStore;
using System.Collections.ObjectModel;
using System.Data.Linq;
using System.Threading;
using System.Windows.Threading;
using System.ComponentModel;

namespace Microsoft.Forums.ForumsClient.ThreadedView
{
    /// <summary>
    /// A container for a post that will be displayed on the UI
    /// This wraps child posts in ObserableCollections and provides 
    /// ability to update data
    /// </summary>
    public class PostContainer
    {
        /// <summary>
        /// Connection string to connect to the database
        /// </summary>
        string connectionString;

        /// <summary>
        /// The dispatcher from the UI thread
        /// </summary>
        Dispatcher dispatcherUI;


        /// <summary>
        /// Post contained in this post container
        /// </summary>
        public Post Post
        {
            get;
            private set;
        }

        /// <summary>
        /// Collection of child posts which get lazy loaded on demand
        /// </summary>
        public DispatchingObservableCollection<PostContainer> ChildPosts
        {
            get;
            private set;
        }

        /// <summary>
        /// Event to notify listeners when a call to PopulateChildPosts has completed
        /// </summary>
        public event EventHandler PopulateCompleted;

        /// <summary>
        /// Event to notify listeners when a call to MarkAsRead has completed
        /// </summary>
        public event EventHandler MarkAsReadCompleted;

        /// <summary>
        /// Inidicates whether or not this post container has child posts
        /// </summary>
        public bool HasChildren
        {
            get
            {
                return Post.TotalReplies > 0;
            }
        }

        /// <summary>
        /// Create a post container for a given post
        /// 
        /// This constructor assumes that the post object given already has its PostPropertySet loaded
        /// </summary>
        /// <param name="post">Post to create container for</param>
        /// <param name="connection">Connection string to database</param>
        /// <param name="dispatcher">Dispatcher from the UI thread</param>
        public PostContainer(Post post, string connection, Dispatcher dispatcher)
        {
            if (post == null) throw new ArgumentNullException("post", "post must not be null");
            if (dispatcher == null) throw new ArgumentNullException("dispatcher", "dispatcher must not be null");

            dispatcherUI = dispatcher;
            Post = post;
            connectionString = connection;
            ChildPosts = new DispatchingObservableCollection<PostContainer>(dispatcher);
        }


        /// <summary>
        /// Loads all direct decendants of the this post containers Post object
        /// </summary>
        public void PopulateChildPosts()
        {
            ChildPosts.Clear();
            ThreadPool.QueueUserWorkItem(
                    delegate
                    {
                        using (var store = new ForumsOfflineStore(connectionString))
                        {
                            DataLoadOptions dlo = new DataLoadOptions();
                            // Ensure the foreign key objects get loaded
                            dlo.LoadWith<Post>(p => p.PostPropertySet);
                            dlo.LoadWith<Post>(p => p.CreatedBy);
                            store.LoadOptions = dlo;

                            var childPosts = from p in store.Posts
                                             where p.ParentId == Post.Id
                                             select new PostContainer(p, connectionString, dispatcherUI);
                            
                            foreach (var p in childPosts)
                            {
                                ChildPosts.Add(p);
                            }
                        }
                        OnPopulateCompleted();
                    });
        }

        /// <summary>
        /// Clears all direct decendants of the this post containers Post object
        /// </summary>
        public void ClearChildPosts()
        {
            ChildPosts.Clear();
        }

        /// <summary>
        /// Mark the post inside this post container as read.
        /// This modifies both the post object in memory and in the database
        /// </summary>
        public void MarkAsRead()
        {
            if (Post.PostPropertySet.IsRead) return;

            // First update local data
            Post.PostPropertySet.IsRead = true;

            // Update database in background thread
            ThreadPool.QueueUserWorkItem
            (
                delegate
                {
                    // Update database
                    using (var store = new ForumsOfflineStore(connectionString))
                    {

                        var readPost = store.Posts.Single(p => p.Id == Post.Id);
                        readPost.PostPropertySet.IsRead = true;
                        store.SubmitChangesWithMerge();
                    }

                    OnMarkAsReadCompleted();
                }


            );

        }


        /// <summary>
        /// Fires the PopulateCompleted event if anyone is listening to it
        /// </summary>
        private void OnPopulateCompleted()
        {
            if (PopulateCompleted != null)
            {
                PopulateCompleted(this, new EventArgs());
            }
        }


        /// <summary>
        /// Fires the MarkAsReadCompleted event if anyone is listening to it
        /// </summary>
        private void OnMarkAsReadCompleted()
        {
            if (MarkAsReadCompleted != null)
            {
                MarkAsReadCompleted(this, new EventArgs());
            }
        }

    }
}
